// Base on the original type definitions for solidity-parser-antlr 0.2
// by Leonid Logvinov <https://github.com/LogvinovLeon>
//    Alex Browne <https://github.com/albrow>
//    Xiao Liang <https://github.com/yxliang01>

export type ParseResult = SourceUnit & {
    errors?: any[]
    tokens?: Token[]
}

interface Token {
    type: string
    value: string | undefined
    range?: [number, number]
    loc?: {
        start: {
            line: number
            column: number
        }
        end: {
            line: number
            column: number
        }
    }
}


interface Location {
    start: {
        line: number
        column: number
    }
    end: {
        line: number
        column: number
    }
}

export interface BaseASTNode {
    type: ASTNodeTypeString
    range?: [number, number]
    loc?: Location
}

export interface SourceUnit extends BaseASTNode {
    type: 'SourceUnit'
    children: ASTNode[]
}

export interface ContractDefinition extends BaseASTNode {
    type: 'ContractDefinition'
    name: string
    baseContracts: InheritanceSpecifier[]
    kind: string
    subNodes: BaseASTNode[]
}

export interface InheritanceSpecifier extends BaseASTNode {
    type: 'InheritanceSpecifier'
    baseName: UserDefinedTypeName
    arguments: Expression[]
}

export interface UserDefinedTypeName extends BaseASTNode {
    type: 'UserDefinedTypeName'
    namePath: string
}

export type ASTNodeTypeString = typeof astNodeTypes[number]
export interface InvalidNode extends BaseASTNode {
    type: 'InvalidNode'
    name?: string
    value?: string
}
export interface PragmaDirective extends BaseASTNode {
    type: 'PragmaDirective'
    name: string
    value: string
}
export interface ImportDirective extends BaseASTNode {
    type: 'ImportDirective'
    path: string
    pathLiteral: StringLiteral
    unitAlias: string | null
    unitAliasIdentifier: Identifier | null
    symbolAliases: Array<[string, string | null]> | null
    symbolAliasesIdentifiers: Array<[Identifier, Identifier | null]> | null
}
export interface StateVariableDeclaration extends BaseASTNode {
    type: 'StateVariableDeclaration'
    variables: StateVariableDeclarationVariable[]
    initialValue: Expression | null
}
export interface FileLevelConstant extends BaseASTNode {
    type: 'FileLevelConstant'
    typeName: TypeName
    name: string
    initialValue: Expression
    isDeclaredConst: boolean
    isImmutable: boolean
}
export interface UsingForDeclaration extends BaseASTNode {
    type: 'UsingForDeclaration'
    typeName: TypeName | null
    functions: string[]
    libraryName: string | null
    isGlobal: boolean;
}
export interface StructDefinition extends BaseASTNode {
    type: 'StructDefinition'
    name: string
    members: VariableDeclaration[]
}
export interface ModifierDefinition extends BaseASTNode {
    type: 'ModifierDefinition'
    name: string
    parameters: null | VariableDeclaration[]
    isVirtual: boolean
    override: null | UserDefinedTypeName[]
    body: Block | null
}
export interface ModifierInvocation extends BaseASTNode {
    type: 'ModifierInvocation'
    name: string
    arguments: Expression[] | null
}
export interface FunctionDefinition extends BaseASTNode {
    type: 'FunctionDefinition'
    name: string | null
    parameters: VariableDeclaration[]
    modifiers: ModifierInvocation[]
    stateMutability: 'pure' | 'constant' | 'payable' | 'view' | null
    visibility: 'default' | 'external' | 'internal' | 'public' | 'private'
    returnParameters: VariableDeclaration[] | null
    body: Block | null
    override: UserDefinedTypeName[] | null
    isConstructor: boolean
    isReceiveEther: boolean
    isFallback: boolean
    isVirtual: boolean
}

export interface CustomErrorDefinition extends BaseASTNode {
    type: 'CustomErrorDefinition'
    name: string
    parameters: VariableDeclaration[]
}

export interface TypeDefinition extends BaseASTNode {
    type: 'TypeDefinition'
    name: string
    definition: ElementaryTypeName
}

export interface RevertStatement extends BaseASTNode {
    type: 'RevertStatement'
    revertCall: FunctionCall
}
export interface EventDefinition extends BaseASTNode {
    type: 'EventDefinition'
    name: string
    parameters: VariableDeclaration[]
    isAnonymous: boolean
}
export interface EnumValue extends BaseASTNode {
    type: 'EnumValue'
    name: string
}
export interface EnumDefinition extends BaseASTNode {
    type: 'EnumDefinition'
    name: string
    members: EnumValue[]
}
export interface VariableDeclaration extends BaseASTNode {
    type: 'VariableDeclaration'
    isIndexed: boolean
    isStateVar: boolean
    typeName: TypeName | null
    name: string | null
    identifier: Identifier | null
    isDeclaredConst?: boolean
    storageLocation: string | null
    expression: Expression | null
    visibility?: 'public' | 'private' | 'internal' | 'default'
}
export interface StateVariableDeclarationVariable extends VariableDeclaration {
    override: null | UserDefinedTypeName[]
    isImmutable: boolean
}
export interface ArrayTypeName extends BaseASTNode {
    type: 'ArrayTypeName'
    baseTypeName: TypeName
    length: Expression | null
}
export interface Mapping extends BaseASTNode {
    type: 'Mapping'
    keyType: ElementaryTypeName | UserDefinedTypeName
    valueType: TypeName
}
export interface FunctionTypeName extends BaseASTNode {
    type: 'FunctionTypeName'
    parameterTypes: VariableDeclaration[]
    returnTypes: VariableDeclaration[]
    visibility: string
    stateMutability: string | null
}

export interface Block extends BaseASTNode {
    type: 'Block'
    statements: BaseASTNode[]
}
export interface ExpressionStatement extends BaseASTNode {
    type: 'ExpressionStatement'
    expression: Expression | null
}
export interface IfStatement extends BaseASTNode {
    type: 'IfStatement'
    condition: Expression
    trueBody: Statement
    falseBody: Statement | null
}
export interface UncheckedStatement extends BaseASTNode {
    type: 'UncheckedStatement'
    block: Block
}
export interface TryStatement extends BaseASTNode {
    type: 'TryStatement'
    expression: Expression
    returnParameters: VariableDeclaration[] | null
    body: Block
    catchClauses: CatchClause[]
}
export interface CatchClause extends BaseASTNode {
    type: 'CatchClause'
    isReasonStringType: boolean
    kind: string | null
    parameters: VariableDeclaration[] | null
    body: Block
}
export interface WhileStatement extends BaseASTNode {
    type: 'WhileStatement'
    condition: Expression
    body: Statement
}
export interface ForStatement extends BaseASTNode {
    type: 'ForStatement'
    initExpression: SimpleStatement | null
    conditionExpression?: Expression
    loopExpression: ExpressionStatement
    body: Statement
}
export interface InlineAssemblyStatement extends BaseASTNode {
    type: 'InlineAssemblyStatement'
    language: string | null
    flags: string[]
    body: AssemblyBlock
}
export interface DoWhileStatement extends BaseASTNode {
    type: 'DoWhileStatement'
    condition: Expression
    body: Statement
}
export interface ContinueStatement extends BaseASTNode {
    type: 'ContinueStatement'
}
export interface Break extends BaseASTNode {
    type: 'Break'
}
export interface Continue extends BaseASTNode {
    type: 'Continue'
}
export interface BreakStatement extends BaseASTNode {
    type: 'BreakStatement'
}
export interface ReturnStatement extends BaseASTNode {
    type: 'ReturnStatement'
    expression: Expression | null
}
export interface EmitStatement extends BaseASTNode {
    type: 'EmitStatement'
    eventCall: FunctionCall
}
export interface ThrowStatement extends BaseASTNode {
    type: 'ThrowStatement'
}
export interface VariableDeclarationStatement extends BaseASTNode {
    type: 'VariableDeclarationStatement'
    variables: Array<BaseASTNode | null>
    initialValue: Expression | null
}
export interface ElementaryTypeName extends BaseASTNode {
    type: 'ElementaryTypeName'
    name: string
    stateMutability: string | null
}
export interface FunctionCall extends BaseASTNode {
    type: 'FunctionCall'
    expression: Expression
    arguments: Expression[]
    names: string[]
    identifiers: Identifier[]
}
export interface AssemblyBlock extends BaseASTNode {
    type: 'AssemblyBlock'
    operations: AssemblyItem[]
}
export interface AssemblyCall extends BaseASTNode {
    type: 'AssemblyCall'
    functionName: string
    arguments: AssemblyExpression[]
}
export interface AssemblyLocalDefinition extends BaseASTNode {
    type: 'AssemblyLocalDefinition'
    names: Identifier[] | AssemblyMemberAccess[]
    expression: AssemblyExpression | null
}
export interface AssemblyAssignment extends BaseASTNode {
    type: 'AssemblyAssignment'
    names: Identifier[] | AssemblyMemberAccess[]
    expression: AssemblyExpression
}
export interface AssemblyStackAssignment extends BaseASTNode {
    type: 'AssemblyStackAssignment'
    name: string
    expression: AssemblyExpression
}
export interface LabelDefinition extends BaseASTNode {
    type: 'LabelDefinition'
    name: string
}
export interface AssemblySwitch extends BaseASTNode {
    type: 'AssemblySwitch'
    expression: AssemblyExpression
    cases: AssemblyCase[]
}
export interface AssemblyCase extends BaseASTNode {
    type: 'AssemblyCase'
    value: AssemblyLiteral | null
    block: AssemblyBlock
    default: boolean
}
export interface AssemblyFunctionDefinition extends BaseASTNode {
    type: 'AssemblyFunctionDefinition'
    name: string
    arguments: Identifier[]
    returnArguments: Identifier[]
    body: AssemblyBlock
}
export interface AssemblyFunctionReturns extends BaseASTNode {
    type: 'AssemblyFunctionReturns'
}
export interface AssemblyFor extends BaseASTNode {
    type: 'AssemblyFor'
    pre: AssemblyBlock | AssemblyExpression
    condition: AssemblyExpression
    post: AssemblyBlock | AssemblyExpression
    body: AssemblyBlock
}
export interface AssemblyIf extends BaseASTNode {
    type: 'AssemblyIf'
    condition: AssemblyExpression
    body: AssemblyBlock
}
export type AssemblyLiteral =
    | StringLiteral
    | DecimalNumber
    | HexNumber
    | HexLiteral
export interface SubAssembly extends BaseASTNode {
    type: 'SubAssembly'
}
export interface AssemblyMemberAccess extends BaseASTNode {
    type: 'AssemblyMemberAccess'
    expression: Identifier
    memberName: Identifier
}
export interface NewExpression extends BaseASTNode {
    type: 'NewExpression'
    typeName: TypeName
}
export interface TupleExpression extends BaseASTNode {
    type: 'TupleExpression'
    components: Array<BaseASTNode | null>
    isArray: boolean
}
export interface NameValueExpression extends BaseASTNode {
    type: 'NameValueExpression'
    expression: Expression
    arguments: NameValueList
}
export interface NumberLiteral extends BaseASTNode {
    type: 'NumberLiteral'
    number: string
    subdenomination:
    | null
    | 'wei'
    | 'szabo'
    | 'finney'
    | 'ether'
    | 'seconds'
    | 'minutes'
    | 'hours'
    | 'days'
    | 'weeks'
    | 'years'
}
export interface BooleanLiteral extends BaseASTNode {
    type: 'BooleanLiteral'
    value: boolean
}
export interface HexLiteral extends BaseASTNode {
    type: 'HexLiteral'
    value: string
    parts: string[]
}
export interface StringLiteral extends BaseASTNode {
    type: 'StringLiteral'
    value: string
    parts: string[]
    isUnicode: boolean[]
}
export interface Identifier extends BaseASTNode {
    type: 'Identifier'
    name: string
}

export interface BinaryOperation extends BaseASTNode {
    type: 'BinaryOperation'
    left: Expression
    right: Expression
    operator: BinOp
}
export interface UnaryOperation extends BaseASTNode {
    type: 'UnaryOperation'
    operator: UnaryOp
    subExpression: Expression
    isPrefix: boolean
}
export interface Conditional extends BaseASTNode {
    type: 'Conditional'
    condition: Expression
    trueExpression: Expression
    falseExpression: Expression
}
export interface IndexAccess extends BaseASTNode {
    type: 'IndexAccess'
    base: Expression
    index: Expression
}
export interface IndexRangeAccess extends BaseASTNode {
    type: 'IndexRangeAccess'
    base: Expression
    indexStart?: Expression
    indexEnd?: Expression
}
export interface MemberAccess extends BaseASTNode {
    type: 'MemberAccess'
    expression: Expression
    memberName: string
}
export interface HexNumber extends BaseASTNode {
    type: 'HexNumber'
    value: string
}
export interface DecimalNumber extends BaseASTNode {
    type: 'DecimalNumber'
    value: string
}
export interface NameValueList extends BaseASTNode {
    type: 'NameValueList'
    names: string[]
    identifiers: Identifier[]
    arguments: Expression[]
}

export type ASTNode =
    | SourceUnit
    | PragmaDirective
    | ImportDirective
    | ContractDefinition
    | InheritanceSpecifier
    | StateVariableDeclaration
    | UsingForDeclaration
    | StructDefinition
    | ModifierDefinition
    | ModifierInvocation
    | FunctionDefinition
    | EventDefinition
    | CustomErrorDefinition
    | EnumValue
    | EnumDefinition
    | VariableDeclaration
    | TypeName
    | UserDefinedTypeName
    | Mapping
    | FunctionTypeName
    | Block
    | Statement
    | ElementaryTypeName
    | AssemblyBlock
    | AssemblyCall
    | AssemblyLocalDefinition
    | AssemblyAssignment
    | AssemblyStackAssignment
    | LabelDefinition
    | AssemblySwitch
    | AssemblyCase
    | AssemblyFunctionDefinition
    | AssemblyFunctionReturns
    | AssemblyFor
    | AssemblyIf
    | AssemblyLiteral
    | SubAssembly
    | TupleExpression
    | BinaryOperation
    | Conditional
    | IndexAccess
    | IndexRangeAccess
    | AssemblyItem
    | Expression
    | NameValueList
    | AssemblyMemberAccess
    | CatchClause
    | FileLevelConstant
    | TypeDefinition
    | InvalidNode

export type AssemblyItem =
    | Identifier
    | AssemblyBlock
    | AssemblyExpression
    | AssemblyLocalDefinition
    | AssemblyAssignment
    | AssemblyStackAssignment
    | LabelDefinition
    | AssemblySwitch
    | AssemblyFunctionDefinition
    | AssemblyFor
    | AssemblyIf
    | Break
    | Continue
    | SubAssembly
    | NumberLiteral
    | StringLiteral
    | HexNumber
    | HexLiteral
    | DecimalNumber
export type AssemblyExpression = AssemblyCall | AssemblyLiteral
export type Expression =
    | IndexAccess
    | IndexRangeAccess
    | TupleExpression
    | BinaryOperation
    | Conditional
    | MemberAccess
    | FunctionCall
    | UnaryOperation
    | NewExpression
    | PrimaryExpression
    | NameValueExpression
export type PrimaryExpression =
    | BooleanLiteral
    | HexLiteral
    | StringLiteral
    | NumberLiteral
    | Identifier
    | TupleExpression
    | TypeName
export type SimpleStatement = VariableDeclarationStatement | ExpressionStatement
export type TypeName =
    | ElementaryTypeName
    | UserDefinedTypeName
    | Mapping
    | ArrayTypeName
    | FunctionTypeName
export type Statement =
    | IfStatement
    | WhileStatement
    | ForStatement
    | Block
    | InlineAssemblyStatement
    | DoWhileStatement
    | ContinueStatement
    | BreakStatement
    | ReturnStatement
    | EmitStatement
    | ThrowStatement
    | SimpleStatement
    | VariableDeclarationStatement
    | UncheckedStatement
    | TryStatement
    | RevertStatement

type ASTMap<U> = { [K in ASTNodeTypeString]: U extends { type: K } ? U : never }
type ASTTypeMap = ASTMap<ASTNode>


export const astNodeTypes = [
  'SourceUnit',
  'PragmaDirective',
  'ImportDirective',
  'ContractDefinition',
  'InheritanceSpecifier',
  'StateVariableDeclaration',
  'UsingForDeclaration',
  'StructDefinition',
  'ModifierDefinition',
  'ModifierInvocation',
  'FunctionDefinition',
  'EventDefinition',
  'CustomErrorDefinition',
  'RevertStatement',
  'EnumValue',
  'EnumDefinition',
  'VariableDeclaration',
  'UserDefinedTypeName',
  'Mapping',
  'ArrayTypeName',
  'FunctionTypeName',
  'Block',
  'ExpressionStatement',
  'IfStatement',
  'WhileStatement',
  'ForStatement',
  'InlineAssemblyStatement',
  'DoWhileStatement',
  'ContinueStatement',
  'Break',
  'Continue',
  'BreakStatement',
  'ReturnStatement',
  'EmitStatement',
  'ThrowStatement',
  'VariableDeclarationStatement',
  'ElementaryTypeName',
  'FunctionCall',
  'AssemblyBlock',
  'AssemblyCall',
  'AssemblyLocalDefinition',
  'AssemblyAssignment',
  'AssemblyStackAssignment',
  'LabelDefinition',
  'AssemblySwitch',
  'AssemblyCase',
  'AssemblyFunctionDefinition',
  'AssemblyFunctionReturns',
  'AssemblyFor',
  'AssemblyIf',
  'SubAssembly',
  'TupleExpression',
  'NameValueExpression',
  'BooleanLiteral',
  'NumberLiteral',
  'Identifier',
  'BinaryOperation',
  'UnaryOperation',
  'NewExpression',
  'Conditional',
  'StringLiteral',
  'HexLiteral',
  'HexNumber',
  'DecimalNumber',
  'MemberAccess',
  'IndexAccess',
  'IndexRangeAccess',
  'NameValueList',
  'UncheckedStatement',
  'TryStatement',
  'CatchClause',
  'FileLevelConstant',
  'AssemblyMemberAccess',
  'TypeDefinition',
  'InvalidNode'
] as const




export const binaryOpValues = [
  '+',
  '-',
  '*',
  '/',
  '**',
  '%',
  '<<',
  '>>',
  '&&',
  '||',
  ',,',
  '&',
  ',',
  '^',
  '<',
  '>',
  '<=',
  '>=',
  '==',
  '!=',
  '=',
  ',=',
  '^=',
  '&=',
  '<<=',
  '>>=',
  '+=',
  '-=',
  '*=',
  '/=',
  '%=',
  '|',
  '|=',
] as const
export type BinOp = typeof binaryOpValues[number]

export const unaryOpValues = [
  '-',
  '+',
  '++',
  '--',
  '~',
  'after',
  'delete',
  '!',
] as const
export type UnaryOp = typeof unaryOpValues[number]






